﻿using RM.BasicLibrary.Requests;
using RM.BasicLibrary.Resposes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RM.BasicLibrary.Transfers.TCP
{
    public interface ITcp
    {
        /// <summary>
        /// 设置接受的文件大小 1024*1024*50 接受消息的间隔时间：1000
        /// </summary>
        /// <param name="receiveSize"></param>
        /// <param name="receiveInterval"></param>
        void SetReceive(int receiveSize = 1024 * 1024 * 50, int watchConnectInterval = 1000);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        void Connect(string ip = null, int port = 11000, Action<Socket> connectedHandler = null);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="respose"></param>
        void Send<T>(T request) where T : class;

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TRespose"></typeparam>
        /// <param name="receiveCmdHandler"></param>
        void WatchReceive<TRespose, TRequest>(Action<TRespose, TRequest, Socket> receiveCmdHandler)
            where TRespose : class
            where TRequest : class;
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TRespose"></typeparam>
        /// <param name="receiveCmdHandler"></param>
        void WatchReceive(Action<string, Socket> receiveCmdHandler);
        void WatchReceive(Action<byte[], Socket> receiveCmdHandler);

        void Send<T>(Socket endSocket, T request) where T : class;
    }
    public class TcpClient : ITcp
    {
        private int receiveSize = 1024 * 1024 * 50;
        private int watchConnectInterval = 1000;
        private string HeartPag = "HeartPag";
        /// <summary>
        /// 连接成功处理函数
        /// </summary>
        public Action<Socket> ConnectedHandler { get; set; }
        private Socket socket { get; set; }
        private IPEndPoint Point { get; set; }
        public TcpClient()
        {

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="connectedHandler"></param>
        public void Connect(string ip = null, int port = 11000, Action<Socket> connectedHandler = null)
        {
            ip.NotNull();
            port.NotNull();
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //将获取的IP地址和端口号绑定在网络节点上
            Point = new IPEndPoint(IPAddress.Parse(ip), port);
            Task.Run(() =>
            {
                while (true)//持续监听服务端发来的消息
                {
                    if (!socket.Connected)
                        Root.BasicIns.ExFilter.Execute(() =>
                        {
                            //定义一个套接字监听
                            socket.Connect(Point);
                            connectedHandler?.Invoke(socket);
                        }, exHander: () =>
                        {
                            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        }, ex: null);
                    Thread.Sleep(watchConnectInterval);
                }
            });
        }
        /// <summary>
        /// 实时监听接受消息
        /// </summary>
        /// <param name="receiveCmdHandler"></param>
        /// <param name="connectedHandler"></param>
        public void WatchReceive<TRespose, TRequest>(Action<TRespose, TRequest, Socket> receiveCmdHandler)
                     where TRespose : class
            where TRequest : class
        {
            Receive(receiveCmdHandler);
        }
        public void WatchReceive(Action<byte[], Socket> receiveCmdHandler)
        {
            Task.Run(() =>
            {
                while (true)//持续监听服务端发来的消息
                {
                    Root.BasicIns.ExFilter.Execute(() =>
                    {
                        //定义一个1M的内存缓冲区，用于临时性存储接收到的消息
                        byte[] arrRecvmsg = new byte[receiveSize];
                        //将客户端套接字接收到的数据存入内存缓冲区，并获取长度
                        int length = socket.Receive(arrRecvmsg);
                        //将套接字获取到的字符数组转换为人可以看懂的字符串
                        string strRevMsg = Encoding.UTF8.GetString(arrRecvmsg, 0, length);
                        if (strRevMsg.Contains(HeartPag))
                        {
                            SendHeartPag();
                            return;
                        }
                        receiveCmdHandler?.Invoke(arrRecvmsg.GetValue(0, length) as byte[], socket);
                    });

                }
            });
        }
        public void WatchReceive(Action<string, Socket> receiveCmdHandler)
        {
            Task.Run(() =>
            {
                while (true)//持续监听服务端发来的消息
                {
                    Root.BasicIns.ExFilter.Execute(() =>
                    {
                        //定义一个1M的内存缓冲区，用于临时性存储接收到的消息
                        byte[] arrRecvmsg = new byte[receiveSize];
                        //将客户端套接字接收到的数据存入内存缓冲区，并获取长度
                        int length = socket.Receive(arrRecvmsg);
                        //将套接字获取到的字符数组转换为人可以看懂的字符串
                        string strRevMsg = Encoding.UTF8.GetString(arrRecvmsg, 0, length);
                        if (strRevMsg.Contains(HeartPag))
                        {
                            SendHeartPag();
                            return;
                        }
                        receiveCmdHandler?.Invoke(strRevMsg, socket);
                    });

                }
            });
        }
        private void Receive<TRespose, TRequest>(Action<TRespose, TRequest, Socket> receiveCmdHandler)
            where TRespose : class
            where TRequest : class
        {
            Task.Run(() =>
            {
                while (true)//持续监听服务端发来的消息
                {
                    Root.BasicIns.ExFilter.Execute(() =>
                    {
                        //定义一个1M的内存缓冲区，用于临时性存储接收到的消息
                        byte[] arrRecvmsg = new byte[receiveSize];
                        //将客户端套接字接收到的数据存入内存缓冲区，并获取长度
                        int length = socket.Receive(arrRecvmsg);
                        //将套接字获取到的字符数组转换为人可以看懂的字符串
                        string strRevMsg = Encoding.UTF8.GetString(arrRecvmsg, 0, length);
                        TRespose respose = default(TRespose);
                        TRequest request = default(TRequest);
                        if ((respose.GetType() == typeof(string)) && (request.GetType() == typeof(string)))
                        {
                            receiveCmdHandler?.Invoke(strRevMsg as TRespose, strRevMsg as TRequest, socket);
                            return;
                        }
                        Root.BasicIns.ExFilter.Execute(() =>
                        {
                            respose = Root.BasicIns.JsonSerialize.Deserialize<TRespose>(strRevMsg) as TRespose;
                        });
                        Root.BasicIns.ExFilter.Execute(() =>
                        {
                            request = Root.BasicIns.JsonSerialize.Deserialize<TRespose>(strRevMsg) as TRequest;
                        });
                        if (respose != null && (respose is Request) && (respose as Request).Cmd == HeartPag)
                        {
                            SendHeartPag();
                            return;
                        }
                        receiveCmdHandler?.Invoke(respose, request, socket);
                    });

                }
            });
        }
        private void SendHeartPag()
        {
            Send(new Respose() { Msg = "HeartPag" });
        }
        public void Send<T>(T respose) where T : class
        {
            respose.NotNull();
            string cmd = string.Empty;
            Root.BasicIns.ExFilter.Execute(() =>
            {
                byte[] arrClientSendMsg = null;
                if (!(respose is byte || respose is byte[]))
                {
                    if (!(respose is string))
                        cmd = Root.BasicIns.JsonSerialize.Serialize(respose);
                    else
                        cmd = respose as string;
                    //将输入的内容字符串转换为机器可以识别的字节数组   
                    arrClientSendMsg = Encoding.UTF8.GetBytes(cmd);
                }
                arrClientSendMsg = respose as byte[];
                //调用客户端套接字发送字节数组   
                socket.Send(arrClientSendMsg);
            }, "TCP找不到服务器，发送失败！");
        }

        public void Send<T>(Socket endSocket, T respose) where T : class
        {
            Send(respose);
        }

        public void SetReceive(int receiveSize = 52428800, int watchConnectInterval = 1000)
        {
            this.watchConnectInterval = watchConnectInterval;
            this.receiveSize = receiveSize;
        }


    }
}
